using System;
using System.Collections;
using System.Collections.Generic;
using System.Security.Cryptography;
using UnityEngine;

namespace Nirvana.Common
{
    public class MonoSingleton<T> : MonoBehaviour where T : Component
    {
        private static bool _isApplicationQuitting = false;
        private static GameObject _monoSingletonRoot;
        private static T _instance;
        public static T Instance
        {
            get
            {
                if (_instance == null)
                {
                    if (!Application.isPlaying)
                    {
                        Debug.LogError("[MonoSingleton] Unity is not up and running, cannot create instance! " + typeof(T).Name);
                        return null;
                    }

                    if (_isApplicationQuitting)
                    {
                        Debug.LogError("[MonoSingleton] Singletons are not allowed to be called during game exit! " + typeof(T).Name);
                    }
                    else
                    {
                        Create();
                    }
                }

                return _instance;
            }
        }

        public static T Create()
        {
            if (_instance == null)
            {
                _instance = FindObjectOfType<T>();
                if (_instance == null)
                {
                    if (_monoSingletonRoot == null)
                    {
                        _monoSingletonRoot = new GameObject("MonoSingleton");
                        DontDestroyOnLoad(_monoSingletonRoot);
                    }

                    var singletonObj = new GameObject(typeof(T).Name + " (MonoSingleton)");
                    singletonObj.transform.SetParent(_monoSingletonRoot.transform);
                    _instance = singletonObj.AddComponent<T>();
                }
            }

            return _instance;
        }

        public static bool HasInstance()
        {
            return _instance != null;
        }
        
        protected void Awake()
        {
            if (_instance != null && _instance != this)
            {
                if (Application.isPlaying)
                {
                    Destroy(gameObject);
                }
                else
                {
                    DestroyImmediate(gameObject);
                }
                Debug.LogError("[MonoSingleton] Repeated Instantiated MonoSingleton! GameObject: " + _instance.name);
            }
            else if (_instance == null)
            {
                _instance = GetComponent<T>();
            }
            
            OnInit();
        }

        protected virtual void OnInit() { }
        protected virtual void Update() { }
        protected virtual void OnDestroy() { }
        protected virtual void OnPause() { }

        private void OnApplicationQuit()
        {
            _isApplicationQuitting = true;
            _instance = null;
        }

        private void OnApplicationPause(bool pauseStatus)
        {
            var ins = _instance as MonoSingleton<T>;
            if (ins != null)
            {
                ins.OnPause();
            }
        }
    }
}